package dr.util;

import java.io.File;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import javax.vecmath.Vector2f;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import ai.pathfinder.*;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

import data.Game;
import dr.moteur.BaseAbstraite;
import dr.moteur.Forteresse;
import dr.moteur.GameEngine;
import dr.moteur.Mine;
import dr.moteur.PosteAvance;
import dr.moteur.QG;
import dr.moteur.TourAbstraite;
import dr.moteur.Zone;
import dr.moteur.BaseAbstraite.enumAgent;


/**
 * Cette classe permet d initialiser le jeu a partir d un fichier de configuration xml et de stocker les differentes variables qui seront necessaire pour la mise en place du jeu
 *
 */
public class GameSetup {

	
	/*~~ ATTRIBUTS ~~*/
	/**
	 * stocke le nombre de joueurs autorises indique dans le fichier xml
	 */
	private int nb_joueur_max, nb_joueurs;
	/**
	 * stocke le chemin permettant d acceder a la carte
	 */
	private String map;
	/**
	 * @deprecated
	 */
	private int argent_init_j;
    /**
     * stocke les dimension de la carte
     */
    private int w_map, h_map ;
    /**
     * Graphe representant les bases et les chemins construits entre elles
     */
    public GrapheChemin graphe;
	//private static LinkedList bases_init = null;
	

	/*~~ CONSTRUCTEUR ~~*/
	/**
	 * @param configFile chemin vers le fichier xml a interpreter
	 * @param GE reference au moteur graphique qu il faudra mettre a jour
	 */
	public GameSetup(String configFile, GameEngine GE){
		
			
		nb_joueur_max = 0;
		//bases_init = null;

		// obtention d'un Document Builder qui permet de cr�er de nouveaux
		// documents ou de parser des documents � partir de fichiers
		DocumentBuilder docBuilder = null;

		try {
			docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		} catch(ParserConfigurationException e) {
			System.err.println("Impossible de creer un DocumentBuilder.");
			System.exit(1);
		}
		
		// re-charger ce document a partir du fichier
		Document xml = lireDocument(docBuilder, configFile);
		if(xml == null) System.exit(1);

		if (Game.debug_setup_claire) afficherDocument(xml);
		
		analyser(xml, GE);

		
	}
	/*~~ REDEFINITIONS ~~*/
	
	/*~~ METHODES NON STATIQUES ~~*/
	/**
	 * Lit un document XML a partir d'un fichier sur le disque, et construit
	 * le document DOM correspondant.
	 * 
	 * @param docBuilder une instance de DocumentBuilder
	 * @param nomFichier le fichier ou est stocke le document XML
	 * @return un objet DOM Document correspondant au document XML 
	 */
	private static Document lireDocument(DocumentBuilder docBuilder, 
			String nomFichier) {
		
		try {
			return docBuilder.parse(new File(nomFichier));
		} catch(SAXException e) {
			System.err.println("Erreur de parsing de " + nomFichier);
		} catch (IOException e) {
			System.err.println("Erreur d'entree/sortie sur " + nomFichier);
		}
		
		return null;
	}
	
	/**
	 * Affiche a l'ecran un document XML fourni sous forme d'un objet DOM
	 * Document.
	 * 
	 * @param doc le document
	 */
	private static void afficherDocument(Document doc) {
		Element e = doc.getDocumentElement();
		afficherElement(e);
	}
	
	/**
	 * Affiche a l'ecran un element XML, ainsi que ses attributs, ses noeuds
	 * de texte, et ses sous-elements.
	 * 
	 * @param e l'element a afficher
	 */
	private static void afficherElement(Element e) {
		System.out.print("<" + e.getNodeName() + " ");
		
		NamedNodeMap attr = e.getAttributes();
		for(int i=0; i<attr.getLength(); i++) {
			Attr a = (Attr)attr.item(i);
			System.out.print(a.getName() + "=\"" + a.getNodeValue() + "\" ");
		}
		System.out.println(">");
		
		for(Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) {
			switch(n.getNodeType()) {
			case Node.ELEMENT_NODE:
				afficherElement((Element)n);
				break;
			case Node.TEXT_NODE:
				String data = ((Text)n).getData();
				System.out.print(data);
				break;
			}
		}
		System.out.println("</" + e.getNodeName() + ">");
	}
	
	/**
	 * Analyse le document XML lu afin de retirer les donnees necessaires
	 *  a la mise en place du jeu
	 * 
	 * @param xml le document lu (cree prealablement par le parseur DOM)
	 * @param GE le moteur de GE qu'on va mettre a jour
	 */
	public void analyser(Document xml, GameEngine GE){
				
		Element root_elmt = xml.getDocumentElement();
		
		//~~ porte feuille initial des joueurs
		Node noeud = root_elmt.getElementsByTagName("argent_init").item(0).getFirstChild();
		argent_init_j = Integer.parseInt(noeud.getNodeValue());
		//if (Game.debug_setup_claire) System.out.println("argent init : "+argent_init_j);
		noeud = root_elmt.getElementsByTagName("nb_joueur").item(0).getFirstChild();
		nb_joueurs = Integer.parseInt(noeud.getNodeValue());
		
		//Map
		noeud = root_elmt.getElementsByTagName("image").item(0).getFirstChild();
			//texture et taille
		String image = noeud.getNodeValue();
		map = image.split(" ")[0];
		w_map = Integer.parseInt((image.split(" "))[1]);
		h_map = Integer.parseInt((image.split(" "))[2]);
		if (Game.debug_setup_claire) System.out.println("map texture : "+map);
		if (Game.debug_setup_claire) System.out.println("texture et tailles : "+map+" "+w_map+" "+w_map);
		
			// bases 
		NodeList bases = root_elmt.getElementsByTagName("base");
		if (Game.debug_setup_claire) System.out.println("nb bases : "+bases.getLength());
		this.graphe = new GrapheChemin(bases.getLength());
		int nb_joueur_place = 0;
		for (int i=0; i < bases.getLength(); i++){
			//recupere les attributs
			NamedNodeMap attributs = bases.item(i).getAttributes();
			String depart = attributs.getNamedItem("depart").getNodeValue();
			if (Game.debug_setup_claire) System.out.println("depart "+depart);
			String type = attributs.getNamedItem("type").getNodeValue();
			if (Game.debug_setup_claire) System.out.println("type "+type);
			//recupere les informations 
			NodeList info_base = bases.item(i).getChildNodes();
			String id ="";
			int index =0;
			float posX =0;  float posY = 0;
			String positions="";
			String successeurs=""; 
			String capacite="";
			int capacite_int =0 ;
			//creation de la liste de zone a ajouter
			LinkedList<Zone> liste_zones = new LinkedList<Zone>();
			
			for (int j = 0 ; j < info_base.getLength(); j++){
				//System.out.println(j+" : "+info_base.item(j).getNodeName()+" valeur : "+info_base.item(j).getNodeValue());
				if (info_base.item(j).getNodeName()=="index"){
					id = info_base.item(j).getFirstChild().getNodeValue();
				}else if (info_base.item(j).getNodeName()=="position") {
					positions  = info_base.item(j).getFirstChild().getNodeValue();
					posX  = Float.parseFloat(positions.split(" ")[0]);
					posY  = Float.parseFloat(positions.split(" ")[1]);
				}else if (info_base.item(j).getNodeName()=="successeurs") {
					successeurs = info_base.item(j).getFirstChild().getNodeValue();
				}else if (info_base.item(j).getNodeName()=="capacite") {
					capacite = info_base.item(j).getFirstChild().getNodeValue();
					capacite_int = Integer.parseInt(capacite);
				}else if (info_base.item(j).getNodeName()=="zones"){
					if (Game.debug_setup_claire) System.out.println("on est dans zones");
					NodeList zones = info_base.item(j).getChildNodes();
					if (Game.debug_setup_claire) System.out.println("nb zones : "+zones.getLength());
					Vector2f HG = new Vector2f(); // coin haut gauche de la zone
					Vector2f BD = new Vector2f(); // coin bas droit de la zone
					for (int k = 0 ; k < zones.getLength(); k++){
						if (zones.item(k).getNodeName()=="zone"){
							if (Game.debug_setup_claire) System.out.println("on est ds zone");
							NodeList info_zone = zones.item(k).getChildNodes();
							if (Game.debug_setup_claire) System.out.println(info_zone.getLength());
							for (int l = 0 ; l < info_zone.getLength(); l++){
								if (info_zone.item(l).getNodeName()=="xMin"){
									HG.x = Float.parseFloat(info_zone.item(l).getFirstChild().getNodeValue());
									if (Game.debug_setup_claire) System.out.println("xmin "+info_zone.item(l).getFirstChild().getNodeValue());
								}else if (info_zone.item(l).getNodeName()=="xMax"){
									BD.x = Float.parseFloat(info_zone.item(l).getFirstChild().getNodeValue());
									if (Game.debug_setup_claire) System.out.println("xmax "+info_zone.item(l).getFirstChild().getNodeValue());
								}else if (info_zone.item(l).getNodeName()=="yMin"){
									HG.y = Float.parseFloat(info_zone.item(l).getFirstChild().getNodeValue());
									if (Game.debug_setup_claire) System.out.println("ymin "+info_zone.item(l).getFirstChild().getNodeValue());
								}else if (info_zone.item(l).getNodeName()=="yMax"){
									BD.y = Float.parseFloat(info_zone.item(l).getFirstChild().getNodeValue());
									if (Game.debug_setup_claire) System.out.println("ymax "+info_zone.item(l).getFirstChild().getNodeValue());
								}
								else{if (Game.debug_setup_claire) System.out.println("rien");}
							}
			//				System.out.println("HG "+HG.x+" "+HG.y+" BD "+BD.x+" "+BD.y);
							Zone z = new Zone (HG, BD);
							liste_zones.addLast(z);
						}
					}
					
					

				}/*else{
					System.out.println("pas de correspondance de nom");
				}*/
			}
		//	System.out.println("gamesetup l 243 on va quitter l'appli ");System.exit(0);
				// index
			index = Integer.parseInt(id);
			if (Game.debug_setup_claire) System.out.println("indormations sur cette base : Base "+index);
				//position
			if (Game.debug_setup_claire) System.out.println("							  positions : ("+posX+"; "+posY+") => string positions = "+positions);
				
				//=> CREATION DE LA BASE
			int id_joueur = 0;
			if (depart.equalsIgnoreCase("1")) {
				if (nb_joueur_max < GE.getListeJoueurs().size()){
					id_joueur = nb_joueur_max;
					nb_joueur_max++;
				}
			}
			ai.pathfinder.Node n = new ai.pathfinder.Node(posX, posY);
			BaseAbstraite base;
			if (type.equalsIgnoreCase("QG")){ // QG
				if (Game.debug_setup_claire) System.out.println("creons cette base");
				base = new QG(n, index,-1, null, enumAgent.SCOUT, liste_zones, null, GE, index, this.graphe);
				GE.getListeBases().addLast(base);
				//ajout de la base a la liste du joueur
				if (depart=="1"){
					
				}
				if (Game.debug_display) System.out.println("on test si la liste a été ajoutée");
				Iterator<Zone> iter = base.getListeZones().iterator(); 
			    while (iter.hasNext()){
			    	if (Game.debug_display)System.out.println("on va dessiner la zone");
			    	Zone z = iter.next();
			    }
			}else if (type.equalsIgnoreCase("M")){ //MINE
				if (Game.debug_display) System.out.println("mine");
				base = new Mine(n, index, -1, null, enumAgent.SCOUT, liste_zones, null, GE, index, this.graphe);
				GE.getListeBases().addLast(base);
				Iterator<Zone> iter = base.getListeZones().iterator(); 
			    while (iter.hasNext()){
			    	if (Game.debug_display)System.out.println("on va dessiner la zone");
			    	Zone z = iter.next();
			    }
			}else if (type.equalsIgnoreCase("F")){ //forteresse
				
				base = new Forteresse(n, index, -1, null, enumAgent.SCOUT, liste_zones, null, GE, index, this.graphe);
				GE.getListeBases().addLast(base);
				
				Iterator<Zone> iter = base.getListeZones().iterator(); 
			    while (iter.hasNext()){
			    	if (Game.debug_display)System.out.println("on va dessiner la zone");
			    	Zone z = iter.next();
			    }
			}else if (type.equalsIgnoreCase("Pav")){ //poste avance
				
				base = new PosteAvance(n, index, -1, null, enumAgent.SCOUT, liste_zones, null, GE, index, this.graphe);
				GE.getListeBases().addLast(base);	
				Iterator<Zone> iter = base.getListeZones().iterator(); 
			    while (iter.hasNext()){
			    	if (Game.debug_display)System.out.println("on va dessiner la zone");
			    	Zone z = iter.next();
			    }
			}
			 
			
					
				//successeurs
			String[] liste_succ = successeurs.split(" ");
			int[] succ = new int[liste_succ.length];
			for (int s = 0; s < liste_succ.length; s++){
				//conversion en entier
				succ[s] = Integer.parseInt(liste_succ[s]);
			}
			if (Game.debug_setup_claire) System.out.println("							  Successeurs : "+successeurs);				
			
			//ajout du noeud au graphe
			this.graphe.ajoutNoeud(index, posX, posY, succ);

		}
		
		//Tous les liens sont crees, on finalise le graphe
		this.graphe.finalisation();
		

		
		
		
	}
	
	/*~~ METHODES STATIQUES ~~*/

	/**
	 * @return le chemin indiquant ou se trouve la carte
	 */
	public String get_map() {
		// TODO Auto-generated method stub
		return map;
	}

	/**
	 * @deprecated
	 */
	public int get_argent_init_j() {
		// TODO Auto-generated method stub
		return argent_init_j;
	}

	/**
	 * @return la taille de la map
	 */
	public int get_w_map() {
		return w_map;
	}

	/**
	 * @return la taille de la map
	 */
	public int get_h_map() {
		return h_map;
	}

	/**
	 * @return le graphe representant les chemins que pourront emprunter les agents
	 */
	public GrapheChemin get_graphe() {
		// TODO Auto-generated method stub
		return graphe;
	}
	/**
	 * @return le nombre de joueurs acceptes pour cette carte
	 */
	public int getNb_joueurs() {
		return nb_joueurs;
	}
	
	/*~~ MAIN ~~*/
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//GameSetup gs = new GameSetup("map/test.xml", null);
		Game.main(null);
	}

}

